package org.wattdepot.gdata.kukuicup.updater.energybaselines;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * An abstract data type that holds the baseline data collected and returns the average.
 * @author Philip Johnson
 */
public class BaselineDataSet {
  /** The interior map of a day or hour to the list of values. */
  private Map<Integer, List<Integer>> time2data = new HashMap<Integer, List<Integer>>();
  
  /**
   * Returns the index to be used for storing the hourly baseline data in this ADT.
   * @param date The date of interest. Computed using DAY_OF_WEEK and HOUR_OF_DAY.
   * @return The index, from 0 (Sunday, midnight) to (23*6) + 23 (Saturday, 11pm).  
   */
  public static int convertDateToHourlyIndex(XMLGregorianCalendar date) {
    // DAY_OF_WEEK is one-based, we want it to be zero-based, so subtract one.
    int dayOfWeek = date.toGregorianCalendar().get(Calendar.DAY_OF_WEEK) - 1;
    int hourOfDay = date.toGregorianCalendar().get(Calendar.HOUR_OF_DAY);
    //System.out.format("For %s, Day of week: %s, Hour of Day: %s%n", date, dayOfWeek, hourOfDay);
    return (dayOfWeek * 24) + hourOfDay;
  }
  
  /**
   * Add a new entry.
   * @param time An integer indicating the time (either a day in the week or an hour in the day).
   * @param value The value to be stored.
   */
  public void add(Integer time, Integer value) {
    // Create the interior list if first time.
    if (!time2data.containsKey(time)) {
      time2data.put(time, new ArrayList<Integer>());
    }
    // Now update. 
    time2data.get(time).add(value);
  }
  
  /**
   * Returns the average of all the entries for the specified time. 
   * @param time The time of interest.
   * @return The average of all the entries, or zero if no entries exist.
   */
  public double getAverage(Integer time) {
    // Return zero if there's no data for this time.
    if (!time2data.containsKey(time)) {
      return 0;
    }
    // Otherwise there's data, so compute the average.
    int total = 0;
    for (Integer value : time2data.get(time)) {
      total += value;
    }
    return (double)total / (double)time2data.get(time).size();
  }

  /**
   * Returns the number of entries for the specified time. 
   * @param time The time slot. 
   * @return The number of entries for that time slot. 
   */
  public int getNumEntries(Integer time) {
    // Return zero if there's no data for this time.
    return (time2data.containsKey(time)) ? time2data.get(time).size() : 0; 
  }

  /**
   * Returns the total number of entries stored in this data set.
   * @return The total number of entries.
   */
  public int getTotalEntries() {
    int entries = 0;
    for (List<Integer> intList : time2data.values()) {
      entries += intList.size();
    }
    return entries;
  }
}
